﻿using System.Buffers;

namespace ConsoleApp;

public class DemoSpan
{
    // Span<T> 一种高效且安全的方式来读取和写入内存。有了 ，我们可以直接操作数组、堆栈和堆等内存区域，避免不必要的内存分配和复制，从而提高代码性能和效率
    
    // 数组处理：避免SubArray带来的内存分配3
    public void ArrayDemo()
    {
        // Create an array containing integer data
        var array = new[] { 1, 2, 3, 4, 5 };

        // 零拷贝操作‌：直接操作现有数组内存，避免 SubArray 等方法的额外分配
        var span = array.AsSpan();
        
        span[2] = 10; // Modify the third element's value to 10
        foreach (var num in array)
        {
            Console.Write(num);
        }
        
        // 高效切片‌：通过 Slice() 快速访问子集，适合处理大型数据块
        var subSpan = span.Slice(10, 20); // 无需创建新数组
    }
    
    // 字符串操作：高效处理子字符串而不创建新对象
    // ‌避免字符串分配‌：处理子字符串时直接操作原始字符串内存
    // ‌高性能解析‌：适用于 JSON/XML 解析、日志处理等场景
    
    // 文件I/O：减少读写时的内存复制开销2
    // 减少内存复制‌：读写文件时直接操作缓冲区，降低开销
    //byte[] buffer = new byte[1024];
    //Span<byte> span = buffer.AsSpan();
    // 文件读取到 span 后直接处理
    
    
    // 网络编程：处理网络数据缓冲区 数据包处理‌：解析二进制协议（如 TCP/UDP 数据包）时直接操作内存
    // 内存映射文件：直接操作磁盘上的数据，无需加载整个文件到内存
    public void NetworkDemo()
    {
        var buffer = new byte[1024]; // 网络接收缓冲区
        Span<byte> span = buffer.AsSpan();
        
        // 从网络读取数据到span中
        // 处理或解析数据...
        
        
        //Span<byte> packet = ReceiveNetworkData();
        //int header = BitConverter.ToInt32(packet.Slice(0, 4));
    }
    
    // 栈内存与内存池管理
    // 栈内存分配：使用栈上 Span，避免堆内存分配
    public void StackMemoryDemo()
    {
        Span<int> stackSpan = stackalloc int[10]; // 直接在栈上分配空间
        stackSpan[0] = 1;
        Console.WriteLine(stackSpan[0]);
    }
    

    
    const string StringForSplit = "666,747,200,468,471,395,942,589,87,353,456,536,772,599,552,338,553,925,532,383,668,96,61,125,621,917,774,146,54,885";
    /// <summary>
    /// 字符串拆分和数组类型转换
    /// </summary>
    /// <returns></returns>
    public int[] TestSplitString()
    {
        return StringForSplit.Split(',').Select(x => Convert.ToInt32(x)).ToArray();
    }
    
    /// <summary>
    /// 字符串拆分和数组类型转换
    /// </summary>
    /// <returns></returns>
    public int[] TestSplitStringWithSpan()
    {
        var span = StringForSplit.AsSpan();
        var separator = ",".AsSpan();
        var sepLen = separator.Length;
        int index;
        var result = new List<int>();
        do
        {
            index = span.IndexOf(separator);
            if (index == -1)
            {
                result.Add(int.Parse(span));
            }
            else
            {
                var value = span[..index];
                result.Add(int.Parse(value));
                span = span[(index + sepLen)..];
            }
        } 
        while (index != -1);
        return result.ToArray();
    }
    
    
    const string HtmlCode = @"<html>
<head>
    <meta charset=""utf-8"">
    <title>Test Page</title>
</head>
<body>
    <header>...</header>
    <main>
        <article>
            <h3>Country list</h3>
            <ul>
                <li><span>Australia</span></li>
                <li><span>Brazil</span></li>
                <li><span>Canada</span></li>
                <li><span>China</span></li>
                <li><span>France</span></li>
                <li><span>Germany</span></li>
                <li><span>Japan</span></li>
                <li><span>South Korea</span></li>
                <li><span>United States</span></li>
                <li><span>United Kingdom</span></li>
            </ul>
        </article>
    </main>
    <footer>...</footer>
</body>
</html>";
    
    /// <summary>
    /// 从 HTML 代码中提取文本内容
    /// </summary>
    /// <returns></returns>
    public string[] TestFilterWithSpan()
    {
        const string countryBegin = "<h3>Country list</h3>";
        const string countryEnd = "</ul>";
        const string startTag = "<li><span>";
        const string endTag = "</span>";

        var span = HtmlCode.AsSpan();
        var countrySpan = countryBegin.AsSpan();
        int index = span.IndexOf(countrySpan);
        span = span.Slice(index + countrySpan.Length);
        index = span.IndexOf(countryEnd.AsSpan());
        span = span.Slice(0, index);

        var startTagSpan = startTag.AsSpan();
        var endTagSpan = endTag.AsSpan();
        var startTagLen = startTagSpan.Length;
        var endTagLen = endTagSpan.Length;

        var result = new List<string>();
        while (true)
        {
            index = span.IndexOf(startTagSpan);
            var endIndex = span.IndexOf(endTagSpan);
            if (index == -1 || endIndex ==-1) break;
            var value = span.Slice(index + startTagLen, endIndex -index-startTagLen);
            result.Add(value.ToString());
            span = span.Slice(endIndex + endTagLen);
        }

        return result.ToArray();
    }
    
    // 跨异步边界使用‌：Memory<T> 可安全用于 async/await 上下文，而 Span<T> 因是 ref struct 无法跨异步方法
    // async Task ProcessDataAsync(Memory<byte> buffer) {
    //     await File.ReadAllBytesAsync("data.bin").CopyToAsync(buffer);
    // }

    // 堆内存的长期引用‌
    // ‌托管堆内存管理‌：适合需要长期持有或传递的内存块（如缓存池），避免 Span<T> 的栈生命周期限制
    class DataProcessor {
        private Memory<byte> _persistentBuffer; // 可作为字段存储
    }
    
    // 与内存池（ArrayPool）集成
    // 高效内存复用‌：结合 ArrayPool 减少 GC 压力，适合高频临时内存分配场景
    public void UseArrayPool() {
        var pool = ArrayPool<byte>.Shared;
        Memory<byte> buffer = pool.Rent(1024); // 从池中获取内存块
        // 处理数据...
        pool.Return(buffer.ToArray()); // 归还到池中
    }
    
    // 非连续内存的抽象: 包装非连续存储‌：可封装如 MemoryStream 等非连续内存的数据源，提供统一访问接口
    
    public void SliceAndConcatenate() {
        using var ms = new MemoryStream();
        Memory<byte> memory = ms.GetBuffer().AsMemory(); // 转换为Memory视图
        
        
        // 高效内存切片和拼接
        var buffer = new byte[1024]; // 大缓冲区
        Memory<byte> slice1 = buffer.AsMemory(0, 512); // 取前半部分
        Memory<byte> slice2 = buffer.AsMemory(512, 512); // 取后半部分
        // 可以将多个 Memory<T> 片段拼接或处理，例如通过网络发送
    }
    
    // 区别
    // Memory<T> 适用于需要长期持有或传递的内存块，如缓存池
    // Span<T> 更适合临时数据处理和算法实现，因其栈分配的特性更适合短生命周期操作
}